package com.yanqu.road.server.manager.guess;

import com.mysql.jdbc.log.Log;
import com.yanqu.road.dao.impl.guess.CommonGuessItemDaoImpl;
import com.yanqu.road.dao.impl.guess.CommonGuessMainDaoImpl;
import com.yanqu.road.dao.impl.guess.CommonGuessUserDataDaoImpl;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.enums.eActivityType;
import com.yanqu.road.entity.guess.CommonGuessInitReq;
import com.yanqu.road.entity.guess.CommonGuessRewardItem;
import com.yanqu.road.entity.guess.data.CommonGuessItem;
import com.yanqu.road.entity.guess.data.CommonGuessMain;
import com.yanqu.road.entity.guess.data.CommonGuessUserData;
import com.yanqu.road.entity.guess.emuns.CommonGuessPlayTypeEnum;
import com.yanqu.road.entity.guess.emuns.CommonGuessReceiveFlagTypeEnum;
import com.yanqu.road.entity.guess.emuns.CommonGuessTypeEnum;
import com.yanqu.road.entity.player.CrossUserBaseInfo;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.exception.BusinessException;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.pb.activity.CommonGuessProto;
import com.yanqu.road.server.TempCrossMgr;
import com.yanqu.road.server.manager.activity.ActivityMgr;
import com.yanqu.road.server.manager.activity.suitang.CrossSuiTangMgr;
import com.yanqu.road.server.manager.guess.activitytypehandler.CommonGuessActivityTypeStrategy;
import com.yanqu.road.server.manager.guess.activitytypehandler.handler.CommonGuessSuiTangStrategy;
import com.yanqu.road.server.manager.guess.pb.CommonGuessPb;
import com.yanqu.road.server.manager.guess.playtypehandler.CommonGuessPlayTypeStrategy;
import com.yanqu.road.server.manager.guess.playtypehandler.handler.CommonGuessTopThreeStrategy;
import com.yanqu.road.server.manager.user.CrossUserMgr;
import com.yanqu.road.server.manger.ServerLanguageMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.ListHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 通用竞猜MGR
 */
public class CrossCommonGuessMgr extends TempCrossMgr {

    /**
     * 竞猜主表MPA.K:活动ID,K:分组ID,K:轮次ID,K:战场ID
     */
    private static Map<Integer, Map<Integer, Map<Integer, Map<Integer, CommonGuessMain>>>> guessMainMap  = new ConcurrentHashMap<>();

    /**
     * 竞猜选项MPA.K:活动ID,K:分组ID,K:轮次ID,,K:战场ID,K:objID(商会ID，或者玩家ID)
     */
    private static Map<Integer, Map<Integer, Map<Integer, Map<Integer, Map<String, CommonGuessItem>>>>> guessItemMap  = new ConcurrentHashMap<>();

    /**
     * 竞猜数据。K:活动ID,K:分组ID,K:轮次ID,K:战场ID,K:玩家ID
     */
    private static Map<Integer, Map<Integer, Map<Integer, Map<Integer, Map<Long, CommonGuessUserData>>>>> guessUserDataMap = new ConcurrentHashMap<>();

    /**
     * 竞猜玩法策略MAP
     */
    private static Map<Integer, CommonGuessPlayTypeStrategy> playTypeStrategyMap = new HashMap<>();
    static {
        playTypeStrategyMap.put(CommonGuessPlayTypeEnum.PLAY_TYPE_TOP_THREE.getValue(), new CommonGuessTopThreeStrategy());//玩法1：冠亚季
    }

    /**
     * 活动类型策略MAP
     */
    private static Map<Integer, CommonGuessActivityTypeStrategy> activityTypeStrategyMap = new HashMap<>();
    static {
        activityTypeStrategyMap.put(eActivityType.SuiTang.getValue(), new CommonGuessSuiTangStrategy());//隋唐
    }

    @Override
    public boolean removeExpireData() throws Exception {
        //活动结束，移除内存
        List<Integer> removeActivityIdList = new ArrayList<>();
        for (Map<Integer, Map<Integer, Map<Integer, CommonGuessMain>>> groupMap : guessMainMap.values()) {
            for (Map<Integer, Map<Integer, CommonGuessMain>> roundMap : groupMap.values()) {
                for (Map<Integer, CommonGuessMain> siteIdMap : roundMap.values()) {
                    for (CommonGuessMain main : siteIdMap.values()) {
                        //判断活动是否结束
                        ActivityInfo activityInfo = ActivityMgr.getActivityInfo(main.getActivityId());
                        boolean flag = ActivityMgr.activityInShowTime(activityInfo);
                        if (!flag) {
                            removeActivityIdList.add(main.getActivityId());
                        }
                    }
                }
            }
        }
        for (int activityId : removeActivityIdList) {
            guessMainMap.remove(activityId);
            guessItemMap.remove(activityId);
            guessUserDataMap.remove(activityId);
        }
        return true;
    }

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        //获取正在进行的活动ID
        List<Integer> activityIdList = new ArrayList<>();
        Map<Integer, ActivityInfo> activityInfoMap = ActivityMgr.getActivityMap();
        for (ActivityInfo activityInfo : activityInfoMap.values()) {
            if (ActivityMgr.activityInShowTime(activityInfo)) {
                activityIdList.add(activityInfo.getActivityId());
            }
        }
        if (!activityIdList.isEmpty()) {
            String activityIds = StringUtils.listToString(activityIdList, ",");
            //加载主表
            guessMainMap = new CommonGuessMainDaoImpl().getData(activityIds);
            //加载选项表
            guessItemMap = new CommonGuessItemDaoImpl().getData(activityIds);
            //加载玩家数据
            guessUserDataMap = new CommonGuessUserDataDaoImpl().getData(activityIds);
        }
        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }

    @Override
    public boolean save() {
        //存储主表
        CommonGuessMainDaoImpl commonGuessMainDao = new CommonGuessMainDaoImpl();
        for (Map<Integer, Map<Integer, Map<Integer, CommonGuessMain>>> groupMap : guessMainMap.values()) {
            for (Map<Integer, Map<Integer, CommonGuessMain>> roundMap : groupMap.values()) {
                for (Map<Integer, CommonGuessMain> siteIdMap : roundMap.values()) {
                    for (CommonGuessMain data : siteIdMap.values()) {
                        //存储
                        if (data.isInsertOption()) {
                            commonGuessMainDao.add(data);
                        } else if (data.isUpdateOption()) {
                            commonGuessMainDao.update(data);
                        }
                    }
                }
            }
        }
        //存储选项表
        CommonGuessItemDaoImpl commonGuessItemDao = new CommonGuessItemDaoImpl();
        for (Map<Integer, Map<Integer, Map<Integer, Map<String, CommonGuessItem>>>> groupMap : guessItemMap.values()) {
            for (Map<Integer, Map<Integer, Map<String, CommonGuessItem>>> roundMap : groupMap.values()) {
                for (Map<Integer, Map<String, CommonGuessItem>> siteIdMap : roundMap.values()) {
                    for (Map<String, CommonGuessItem> objIdMap : siteIdMap.values()) {
                        for (CommonGuessItem data : objIdMap.values()) {
                            //存储
                            if (data.isInsertOption()) {
                                commonGuessItemDao.add(data);
                            } else if (data.isUpdateOption()) {
                                commonGuessItemDao.update(data);
                            }
                        }
                    }
                }
            }
        }
        //储存玩家数据
        CommonGuessUserDataDaoImpl commonGuessUserDataDao = new CommonGuessUserDataDaoImpl();
        for (Map<Integer, Map<Integer, Map<Integer, Map<Long, CommonGuessUserData>>>> groupMap : guessUserDataMap.values()) {
            for (Map<Integer, Map<Integer, Map<Long, CommonGuessUserData>>> roundMap : groupMap.values()) {
                for (Map<Integer, Map<Long, CommonGuessUserData>> siteIdMap : roundMap.values()) {
                    for (Map<Long, CommonGuessUserData> userMap : siteIdMap.values()) {
                        for (CommonGuessUserData data : userMap.values()) {
                            //存储
                            if (data.isInsertOption()) {
                                commonGuessUserDataDao.add(data);
                            } else if (data.isUpdateOption()) {
                                commonGuessUserDataDao.update(data);
                            }
                        }
                    }
                }
            }
        }
        return true;
    }

    /**
     * 获取竞猜主数据
     * @param activityId
     * @param groupId
     * @param roundId
     * @param siteId
     * @return
     */
    public static CommonGuessMain getGuessMain(int activityId, int groupId, int roundId, int siteId) {
        Map<Integer, Map<Integer, Map<Integer, CommonGuessMain>>> groupMap = guessMainMap.get(activityId);
        if (groupMap != null) {
            Map<Integer, Map<Integer, CommonGuessMain>> roundMap = groupMap.get(groupId);
            if (roundMap != null) {
                Map<Integer, CommonGuessMain> siteIdMap = roundMap.get(roundId);
                if (siteIdMap != null) {
                    return siteIdMap.get(siteId);
                }
            }
        }
        return null;
    }

    /**
     * 获取玩家的竞猜数据
     * @param activityId
     * @param groupId
     * @param roundId
     * @param siteId
     * @param userId
     * @return
     */
    public static CommonGuessUserData getUserGuessData(int activityId, int groupId, int roundId, int siteId, long userId) {
        Map<Integer, Map<Integer, Map<Integer, Map<Long, CommonGuessUserData>>>> groupMap = guessUserDataMap.get(activityId);
        if (groupMap != null) {
            Map<Integer, Map<Integer, Map<Long, CommonGuessUserData>>> roundMap = groupMap.get(groupId);
            if (roundMap != null) {
                Map<Integer, Map<Long, CommonGuessUserData>> siteMap = roundMap.get(roundId);
                if (siteMap != null) {
                    Map<Long, CommonGuessUserData> userMap = siteMap.get(siteId);
                    if (userMap != null) {
                        return userMap.get(userId);
                    }
                }
            }
        }
        return null;
    }

    /**
     * 初始化竞猜数据
     * @param req
     * @return
     */
    public static synchronized boolean initData(CommonGuessInitReq req) {
        //判断参数是否正确
        if (req.getActivityId() <= 0) {
            getLogger().error("通用竞猜初始化-活动ID错误：{}", req);
            return false;
        }
        if (req.getTypeEnum() == null) {
            getLogger().error("通用竞猜初始化-类型错误：{}", req);
            return false;
        }
        if (req.getPlayTypeEnum() == null) {
            getLogger().error("通用竞猜初始化-玩法类型错误：{}", req);
            return false;
        }
        if (req.getStartTime() <= 0) {
            getLogger().error("通用竞猜初始化-竞猜开始时间错误：{}", req);
            return false;
        }
        if (req.getEndTime() <= 0) {
            getLogger().error("通用竞猜初始化-竞猜结束时间错误：{}", req);
            return false;
        }
        if (req.getRewardList() == null || req.getRewardList().isEmpty()) {
            getLogger().error("通用竞猜初始化-竞猜奖励错误：{}", req);
            return false;
        }
        if (req.getObjIdList() == null || req.getObjIdList().isEmpty()) {
            getLogger().error("通用竞猜初始化-竞猜对象池子错误：{}", req);
            return false;
        }

        //玩法策略数据检测
        CommonGuessPlayTypeStrategy playTypeStrategy = playTypeStrategyMap.get(req.getPlayTypeEnum().getValue());
        if (playTypeStrategy == null) {
            getLogger().error("通用竞猜初始化-玩法策略不存在：{}", req);
            return false;
        }
        if (!playTypeStrategy.initCheck(req)) {
            return false;
        }

        //判断数据是否存在
        CommonGuessMain guessMain = getGuessMain(req.getActivityId(), req.getGroupId(), req.getRound(), req.getSiteId());
        if (guessMain != null) {
            getLogger().error("通用竞猜初始化-竞猜已经初始化过：{}", req);
            return false;
        }

        //初始化
        guessMain = new CommonGuessMain(
                req.getActivityId(),
                req.getGroupId(),
                req.getRound(),
                req.getSiteId(),
                req.getTypeEnum().getValue(),
                req.getPlayTypeEnum().getValue(),
                req.getPlayTypeEnum().getGuessNum(),
                req.getStartTime(),
                req.getEndTime(),
                req.getEndWaitResultTime(),
                req.getEndShowTime(),
                req.getRewardList());
        Map<Integer, Map<Integer, Map<Integer, CommonGuessMain>>> groupMap = guessMainMap.computeIfAbsent(guessMain.getActivityId(), k -> new ConcurrentHashMap<>());
        Map<Integer, Map<Integer, CommonGuessMain>> roundMap = groupMap.computeIfAbsent(guessMain.getGroupId(), k -> new ConcurrentHashMap<>());
        Map<Integer, CommonGuessMain> siteMap = roundMap.computeIfAbsent(guessMain.getRound(), k -> new ConcurrentHashMap<>());
        siteMap.put(guessMain.getSiteId(), guessMain);
        //竞猜选项
        Map<Integer, Map<Integer, Map<Integer, Map<String, CommonGuessItem>>>> groupItemMap = guessItemMap.computeIfAbsent(req.getActivityId(), k -> new ConcurrentHashMap<>());
        Map<Integer, Map<Integer, Map<String, CommonGuessItem>>> roundItemMap = groupItemMap.computeIfAbsent(req.getGroupId(), k -> new ConcurrentHashMap<>());
        Map<Integer, Map<String, CommonGuessItem>> siteItemMap = roundItemMap.computeIfAbsent(req.getRound(), k -> new ConcurrentHashMap<>());
        Map<String, CommonGuessItem> objIdMap = siteItemMap.computeIfAbsent(req.getSiteId(), k -> new ConcurrentHashMap<>());
        for (String objId : req.getObjIdList()) {
            CommonGuessItem guessItem = new CommonGuessItem(guessMain.getActivityId(), guessMain.getGroupId(), guessMain.getRound(), guessMain.getSiteId(), objId);
            objIdMap.put(objId, guessItem);
        }
        return true;
    }

    /**
     * 更新排名结果
     * @param activityId
     * @param groupId
     * @param round
     * @param siteId
     * @param rankList
     */
    public static void updateRankResult(int activityId, int groupId, int round, int siteId, List<String> rankList) {
        CommonGuessMain guessMain = getGuessMain(activityId, groupId, round, siteId);
        Map<String, CommonGuessItem> itemMap = getGuessItemMap(activityId, groupId, round, siteId);
        if (guessMain == null || itemMap == null || itemMap.size() <= 0) {
            getLogger().error("通用竞猜更新竞猜结果-竞猜不存在：{},{},{},{}", activityId, groupId, round, siteId);
            return;
        }
        if (!StringUtils.isNullOrEmpty(guessMain.getRankResult())) {
            getLogger().error("通用竞猜更新竞猜结果-竞猜结果已经存在：{},{},{},{}", activityId, groupId, round, siteId);
            return;
        }
        if (rankList == null || rankList.isEmpty()) {
            getLogger().error("通用竞猜更新竞猜结果-竞猜结果未空：{},{},{},{},{}", activityId, groupId, round, siteId, rankList);
            return;
        }
        //判断是否在不在竞猜时间
        long now = System.currentTimeMillis();
        if (!(now >= guessMain.getEndTime() && now <= guessMain.getEndShowTime())) {
            getLogger().error("通用竞猜更新竞猜结果-竞猜结果更新时间错误：{},{}", guessMain, now);
            return;
        }
        //取玩法的前几名就行
        CommonGuessPlayTypeEnum playTypeEnum = CommonGuessPlayTypeEnum.getEnumInfo(guessMain.getPlayType());
        if (playTypeEnum == null) {
            getLogger().error("通用竞猜更新竞猜结果-竞猜玩法不存在：{}", guessMain);
            return;
        }
        List<String> resultRankList = new ArrayList<>();
        for (int i = 0; i < playTypeEnum.getGuessNum(); i++) {
            resultRankList.add(rankList.get(i));
        }
        //判断竞猜结果选项是否正确
        boolean checkNumFlag = CommonGuessPlayTypeEnum.checkSelectObjIdNum(guessMain.getPlayType(), resultRankList.size());
        if (!checkNumFlag) {
            getLogger().error("通用竞猜更新竞猜结果-竞猜结果数量不正确：{},{},{},{},{}", activityId, groupId, round, siteId, resultRankList);
            return;
        }
        //判断选择的竞猜结果是否在池子中
        for (String objId : resultRankList) {
            if (!itemMap.containsKey(objId)) {
                getLogger().error("通用竞猜更新竞猜结果-竞猜结果不在选项池子中：{},{},{},{},{},{}", activityId, groupId, round, siteId, resultRankList, objId);
                return;
            }
        }
        //更新竞猜结果
        String rankResult = StringUtils.listToString(resultRankList, ",");
        guessMain.setRankResult(rankResult);
    }

    /**
     * 获取竞猜选项MAP
     * @param activityId
     * @param groupId
     * @param round
     * @param siteId
     * @return
     */
    public static Map<String, CommonGuessItem> getGuessItemMap(int activityId, int groupId, int round, int siteId) {
        Map<Integer, Map<Integer, Map<Integer, Map<String, CommonGuessItem>>>> groupItemMap = guessItemMap.get(activityId);
        if (groupItemMap != null) {
            Map<Integer, Map<Integer, Map<String, CommonGuessItem>>> roundItemMap = groupItemMap.get(groupId);
            if (roundItemMap != null) {
                Map<Integer, Map<String, CommonGuessItem>> siteItemMap = roundItemMap.get(round);
                if (siteItemMap != null) {
                    return siteItemMap.get(siteId);
                }
            }
        }
        return null;
    }

    /**
     * 公用check
     * @param userId
     * @param activityId
     * @param groupId
     * @param round
     * @param siteId
     * @throws BusinessException
     */
    public static void commonCheck(long userId, int activityId, int groupId, int round, int siteId) throws BusinessException {
        //判断活动是否存在
        ActivityInfo activityInfo = ActivityMgr.getActivityInfo(activityId);
        if (activityInfo == null) {
            throw BusinessException.newException(GameErrorCode.E_COMMON_GUESS_NOT_FIND_ACTIVITY);
        }
        //判断活动是否进行中
        if (!ActivityMgr.activityInShowTime(activityInfo)) {
            throw BusinessException.newException(GameErrorCode.E_COMMON_GUESS_ACTIVITY_NOT_IN_SHOW_TIME);
        }
        //获取主数据
        CommonGuessMain guessMain = getGuessMain(activityId, groupId, round, siteId);
        if (guessMain == null) {
            throw BusinessException.newException(GameErrorCode.E_COMMON_GUESS_NOT_FIND_GUESS_DATA);
        }
        //获取竞猜选项
        Map<String, CommonGuessItem> guessItemMap = getGuessItemMap(activityId, groupId, round, siteId);
        if (guessItemMap == null || guessItemMap.isEmpty()) {
            throw BusinessException.newException(GameErrorCode.E_COMMON_GUESS_NOT_FIND_GUESS_ITEM);
        }
        //活动检测,没配置该策略的情况下，默认是通过检测
        CommonGuessActivityTypeStrategy activityTypeStrategy = activityTypeStrategyMap.get(activityInfo.getType());
        if (activityTypeStrategy != null) {
            int code = activityTypeStrategy.check(activityId, userId);
            if (code != 0) {
                throw BusinessException.newException(code);
            }
        }
    }

    /**
     * 获取竞猜数据
     * @param reqMsg
     * @return
     * @throws BusinessException
     */
    public static CommonGuessProto.CommonGuessData.Builder getData(long userId, int groupId, CommonGuessProto.CommonGuessGetDataReqMsg reqMsg) throws BusinessException {
        commonCheck(userId, reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId());
        //获取主数据
        CommonGuessMain guessMain = getGuessMain(reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId());
        //获取竞猜选项
        Map<String, CommonGuessItem> guessItemMap = getGuessItemMap(reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId());
        //玩家竞猜数据
        CommonGuessUserData guessUserData = getUserGuessData(reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId(), userId);
        //构造返回PB
        return CommonGuessPb.buildCommonGuessData(guessMain, guessItemMap, guessUserData);
    }

    /**
     * 保存数据检测
     * @param reqMsg
     * @throws BusinessException
     */
    public static void saveData(long userId, int groupId, CommonGuessProto.CommonGuessSaveDataReqCrossMsg reqMsg) throws BusinessException {
        //存储userBase
        if(reqMsg.hasPlayerBaseData()){
            UserBaseInfo userBaseInfo = PlayerBasePb.parseToUserBaseInfo(reqMsg.getPlayerBaseData());
            CrossUserMgr.updateUserBaseInfo(userId, userBaseInfo);
        }
        //公用check
        commonCheck(userId, reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId());
        //获取主数据
        CommonGuessMain guessMain = getGuessMain(reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId());
        //锁一下
        synchronized (guessMain) {
            //选项
            Map<String, CommonGuessItem> itemMap = getGuessItemMap(reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId());
            //判断是否在竞猜时间
            long now = System.currentTimeMillis();
            if (now < guessMain.getStartTime() || now > guessMain.getEndTime()) {
                throw BusinessException.newException(GameErrorCode.E_COMMON_GUESS_NOT_IN_GUESS_TIME);
            }
            //判断选择的竞猜数是否正确
            if (!CommonGuessPlayTypeEnum.checkSelectObjIdNum(guessMain.getPlayType(), reqMsg.getObjIdsList().size())) {
                throw BusinessException.newException(GameErrorCode.E_COMMON_GUESS_SELECT_OBJ_NUM_ERROR);
            }
            //判断选择的竞猜objId是否在池子中
            for (String objId : reqMsg.getObjIdsList()) {
                if (!itemMap.containsKey(objId)) {
                    throw BusinessException.newException(GameErrorCode.E_COMMON_GUESS_SELECT_OBJ_NOT_IN_POOL);
                }
            }
            //获取已有的选择
            CommonGuessUserData guessUserData = getUserGuessData(reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId(), userId);
            Set<String> myObjIdSet = new HashSet<>();
            if (guessUserData != null && !StringUtils.isNullOrEmpty(guessUserData.getObjIds())) {
                myObjIdSet = StringUtils.stringToSet2(guessUserData.getObjIds(), ",");
            }
            //增加选项选择次数
            Set<String> newObjIdSet = new HashSet<>();
            for (String objId : reqMsg.getObjIdsList()) {
                CommonGuessItem item = itemMap.get(objId);
                //判断选择的是否没变
                if (!myObjIdSet.contains(objId)) {
                    //变了，加
                    item.setGuessUserNum(item.getGuessUserNum() + 1);
                }
                newObjIdSet.add(objId);
            }
            //减少选项选择次数
            for (String myObjId :   myObjIdSet) {
                //判断选择的是否被取消
                if (!newObjIdSet.contains(myObjId)) {
                    CommonGuessItem item = itemMap.get(myObjId);
                    //变了，减
                    item.setGuessUserNum(item.getGuessUserNum() - 1);
                }
            }
            //存储
            putGuessUserData(reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId(), userId, StringUtils.listToString(reqMsg.getObjIdsList(), ","));
        }
    }

    /**
     * 存储竞猜选项
     * @param activityId
     * @param roundId
     * @param siteId
     * @param objIds
     */
    private static void putGuessUserData(int activityId, int groupId, int roundId, int siteId, long useId, String objIds) {
        Map<Integer, Map<Integer, Map<Integer, Map<Long, CommonGuessUserData>>>> groupMap = guessUserDataMap.computeIfAbsent(activityId, k -> new ConcurrentHashMap<>());
        Map<Integer, Map<Integer, Map<Long, CommonGuessUserData>>> roundData = groupMap.computeIfAbsent(groupId, k -> new ConcurrentHashMap<>());
        Map<Integer, Map<Long, CommonGuessUserData>> siteMap = roundData.computeIfAbsent(roundId, k -> new ConcurrentHashMap<>());
        Map<Long, CommonGuessUserData> userMap = siteMap.computeIfAbsent(siteId, k -> new ConcurrentHashMap<>());
        CommonGuessUserData guessUserData = userMap.get(useId);
        if (guessUserData == null) {
            guessUserData = new CommonGuessUserData(useId, activityId, groupId, roundId, siteId, objIds);
            userMap.put(useId, guessUserData);
        } else {
            guessUserData.setObjIds(objIds);
        }
    }

    /**
     * 获取玩家命中的奖项
     * @param activityId
     * @param groupId
     * @param roundId
     * @param siteId
     * @param useId
     * @return
     */
    private static CommonGuessRewardItem getUserHitRewardItem(int activityId, int groupId, int roundId, int siteId, long useId) {
        //获取主数据
        CommonGuessMain guessMain = getGuessMain(activityId, groupId, roundId, siteId);
        //获取竞猜选项
        Map<String, CommonGuessItem> itemMap = getGuessItemMap(activityId, groupId, roundId, siteId);
        if (guessMain != null && !StringUtils.isNullOrEmpty(guessMain.getRankResult()) && itemMap != null && !itemMap.isEmpty()) {
            //获取玩家选项数据
            CommonGuessUserData guessUserData = getUserGuessData(activityId, groupId, roundId, siteId, useId);
            if (guessUserData != null && !StringUtils.isNullOrEmpty(guessUserData.getObjIds())) {
                //获取玩家命中的奖项
                CommonGuessPlayTypeStrategy playTypeStrategy = playTypeStrategyMap.get(guessMain.getPlayType());
                if (playTypeStrategy != null) {
                    return playTypeStrategy.getRewardItem(guessUserData.getObjIds(), guessMain, itemMap);
                }
            }
        }
        return null;
    }

    /**
     * 获取奖励列表
     * @param reqMsg
     * @return
     * @throws BusinessException
     */
    public static CommonGuessProto.CommonGuessRewardListRespMsg.Builder getRewardList(long userId, int groupId, CommonGuessProto.CommonGuessRewardListReqMsg reqMsg) throws BusinessException {
        //公用check
        commonCheck(userId, reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId());
        //获取主数据
        CommonGuessMain guessMain = getGuessMain(reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId());
        CommonGuessProto.CommonGuessRewardListRespMsg.Builder respMsg = CommonGuessProto.CommonGuessRewardListRespMsg.newBuilder();
        //获取玩家命中的奖项
        CommonGuessRewardItem hitRewardItem = getUserHitRewardItem(reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId(), userId);
        respMsg.setRet(0);
        for (CommonGuessRewardItem rewardItem : guessMain.getReward()) {
            CommonGuessProto.CommonGuessRewardItem.Builder rewardItemBuilder = CommonGuessProto.CommonGuessRewardItem.newBuilder();
            rewardItemBuilder.setId(rewardItem.getId());
            rewardItemBuilder.setName(ServerLanguageMgr.getContent(rewardItem.getName(), reqMsg.getLanguage()));
            rewardItemBuilder.setReward(rewardItem.getReward());
            if (hitRewardItem != null && hitRewardItem.getId() == rewardItem.getId()) {
                rewardItemBuilder.setHitFlag(true);
            } else {
                rewardItemBuilder.setHitFlag(false);
            }
            int completeNum = getRewardCompleteUserNum(guessMain.getActivityId(), guessMain.getGroupId(), guessMain.getRound(), guessMain.getSiteId(), rewardItem.getId());
            rewardItemBuilder.setCompleteNum(completeNum);
            respMsg.addReward(rewardItemBuilder);
        }
        respMsg.setResultFlag(!StringUtils.isNullOrEmpty(guessMain.getRankResult()));
        return respMsg;
    }

    /**
     * 领取奖励
     * @param reqMsg
     * @return
     * @throws BusinessException
     */
    public static String receiveReward(long userId, int groupId, CommonGuessProto.CommonGuessReceiveRewardReqMsg reqMsg) throws BusinessException {
        //公用check
        commonCheck(userId, reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId());
        //获取主数据
        CommonGuessMain guessMain = getGuessMain(reqMsg.getActivityId(),groupId, reqMsg.getRound(), reqMsg.getSiteId());
        //获取竞猜选项
        Map<String, CommonGuessItem> itemMap = getGuessItemMap(reqMsg.getActivityId(),groupId, reqMsg.getRound(), reqMsg.getSiteId());
        //判断是否在竞猜领奖期
        long now = System.currentTimeMillis();
        if (now < guessMain.getEndWaitResultTime() || now > guessMain.getEndShowTime()) {
            throw BusinessException.newException(GameErrorCode.E_COMMON_GUESS_NOT_IN_RECEIVE_TIME);
        }
        //判断一下排名是否出来
        if (StringUtils.isNullOrEmpty(guessMain.getRankResult())) {
            throw BusinessException.newException(GameErrorCode.E_COMMON_GUESS_NOT_FIND_RANK_RESULT);
        }
        //判断是否有选择竞猜数据
        CommonGuessUserData guessUserData = getUserGuessData(reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId(), userId);
        if (guessUserData == null || StringUtils.isNullOrEmpty(guessUserData.getObjIds())) {
            throw BusinessException.newException(GameErrorCode.E_COMMON_GUESS_USER_GUESS_DATA_NOT_FOUND);
        }
        List<String> myObjIds = StringUtils.stringToStringList(guessUserData.getObjIds(), ",");
        //判断选择的竞猜数是否正确
        if (!CommonGuessPlayTypeEnum.checkSelectObjIdNum(guessMain.getPlayType(), myObjIds.size())) {
            throw BusinessException.newException(GameErrorCode.E_COMMON_GUESS_SELECT_OBJ_NUM_ERROR);
        }
        //判断选择的竞猜objId是否在池子中
        for (String objId : myObjIds) {
            if (!itemMap.containsKey(objId)) {
                throw BusinessException.newException(GameErrorCode.E_COMMON_GUESS_SELECT_OBJ_NOT_IN_POOL);
            }
        }
        //锁一下
        synchronized (guessUserData) {
            //判断奖励是否领取过
            if (guessUserData.getGetRewardFlag() != CommonGuessReceiveFlagTypeEnum.TYPE_NOT.getValue()) {
                throw new BusinessException(GameErrorCode.E_COMMON_GUESS_RECEIVE_REWARD_ALREADY);
            }
            //存储领取状态
            guessUserData.setGetRewardFlag(CommonGuessReceiveFlagTypeEnum.TYPE_GOT.getValue());
            //根据playType做策略，获取竞猜奖励
            String reward = "";
            CommonGuessPlayTypeStrategy playTypeStrategy = playTypeStrategyMap.get(guessMain.getPlayType());
            if (playTypeStrategy != null) {
                CommonGuessRewardItem rewardItem = playTypeStrategy.getRewardItem(guessUserData.getObjIds(), guessMain, itemMap);
                if (rewardItem != null) {
                    reward = rewardItem.getReward();
                }
            }
            return reward;
        }
    }

    /**
     * 缓存一下玩家中奖的数据
     * @param guessMain
     */
    private static void cacheRewardCompleteUserMap(CommonGuessMain guessMain) {
        if (guessMain == null) {
            return;
        }
        //锁一下
        synchronized (guessMain) {
            if (StringUtils.isNullOrEmpty(guessMain.getRankResult())) {
                return;
            }
            if (!guessMain.getRewardCompleteUserMap().isEmpty()) {
                return;
            }
            Map<Integer, Map<Integer, Map<Integer, Map<Long, CommonGuessUserData>>>> groupMap = guessUserDataMap.get(guessMain.getActivityId());
            if (groupMap == null) {
                return;
            }
            Map<Integer, Map<Integer, Map<Long, CommonGuessUserData>>> roundMap = groupMap.get(guessMain.getGroupId());
            if (roundMap == null) {
                return;
            }
            Map<Integer, Map<Long, CommonGuessUserData>> siteMap = roundMap.get(guessMain.getRound());
            if (siteMap == null) {
                return;
            }
            Map<Long, CommonGuessUserData> userMap = siteMap.get(guessMain.getSiteId());
            if (userMap == null) {
                return;
            }
            //玩法策略
            CommonGuessPlayTypeStrategy playTypeStrategy = playTypeStrategyMap.get(guessMain.getPlayType());
            if (playTypeStrategy == null) {
                return;
            }
            Map<String, CommonGuessItem> itemMap = getGuessItemMap(guessMain.getActivityId(), guessMain.getGroupId(), guessMain.getRound(), guessMain.getSiteId());
            if (itemMap == null) {
                return;
            }

            //遍历玩家，判断玩家中了第几档奖励
            Map<Integer, List<CrossUserBaseInfo>> rewardCompleteUserMap = new ConcurrentHashMap<>();
            for (CommonGuessUserData guessUserData : userMap.values()) {
                String userObjIds = guessUserData.getObjIds();
                //中奖的信息
                CommonGuessRewardItem rewardItem = playTypeStrategy.getRewardItem(userObjIds, guessMain, itemMap);
                if (rewardItem == null) {
                    continue;
                }
                //玩家注入中奖档位
                CrossUserBaseInfo crossUserBaseInfo = CrossUserMgr.getCrossUserBaseInfo(guessUserData.getUserId());
                List<CrossUserBaseInfo> rewardUserList = rewardCompleteUserMap.computeIfAbsent(rewardItem.getId(), k -> new ArrayList<>());
                rewardUserList.add(crossUserBaseInfo);
            }
            guessMain.setRewardCompleteUserMap(rewardCompleteUserMap);
        }
    }

    /**
     * 获取奖励项完成的玩家数量
     * @param activityId
     * @param groupId
     * @param roundId
     * @param siteId
     * @param rewardId
     * @return
     */
    private static int getRewardCompleteUserNum(int activityId, int groupId, int roundId, int siteId, int rewardId) {
        CommonGuessMain guessMain = getGuessMain(activityId, groupId, roundId, siteId);
        if (guessMain == null) {
            return 0;
        }
        Map<Integer, List<CrossUserBaseInfo>> rewardCompleteUserMap = guessMain.getRewardCompleteUserMap();
        if (rewardCompleteUserMap.size() <= 0 && !StringUtils.isNullOrEmpty(guessMain.getRankResult())) {
            //缓存一下 rewardCompleteUserMap
            cacheRewardCompleteUserMap(guessMain);
        }
        List<CrossUserBaseInfo> list = guessMain.getRewardCompleteUserMap().get(rewardId);
        return list == null ? 0 : list.size();
    }

    /**
     * 获取奖励项完成的玩家列表
     * @param userId
     * @param groupId
     * @param reqMsg
     * @return
     * @throws BusinessException
     */
    public static CommonGuessProto.CommonGuessRewardCompleteUserRespMsg.Builder getRewardCompleteUserList(long userId, int groupId, CommonGuessProto.CommonGuessRewardCompleteUserReqMsg reqMsg) throws BusinessException {
        //公用check
        commonCheck(userId, reqMsg.getActivityId(), groupId, reqMsg.getRound(), reqMsg.getSiteId());
        //获取主数据
        CommonGuessMain guessMain = getGuessMain(reqMsg.getActivityId(),groupId, reqMsg.getRound(), reqMsg.getSiteId());
        //奖励项达成的玩家MAP
        Map<Integer, List<CrossUserBaseInfo>> rewardCompleteUserMap = guessMain.getRewardCompleteUserMap();
        if (rewardCompleteUserMap.size() <= 0) {
            //缓存一下 rewardCompleteUserMap
            cacheRewardCompleteUserMap(guessMain);
        }
        //档位玩家LIST
        List<CrossUserBaseInfo> list = guessMain.getRewardCompleteUserMap().get(reqMsg.getId());
        List<CrossUserBaseInfo> pageList = new ArrayList<>();
        if (list != null && !list.isEmpty()) {
            //分页
            int pageSize = reqMsg.hasPageNum() ? reqMsg.getPageNum() : 10;
            int pageNo = reqMsg.hasNum() ? reqMsg.getNum() : 1;
            pageList = ListHelper.paginate(list, pageSize, pageNo);
        }
        //返回PB
        CommonGuessProto.CommonGuessRewardCompleteUserRespMsg.Builder respMsg = CommonGuessProto.CommonGuessRewardCompleteUserRespMsg.newBuilder();
        respMsg.setRet(0);
        for (CrossUserBaseInfo userBaseInfo : pageList) {
            CommonGuessProto.CommonGuessRewardCompleteUserItem.Builder userItem = CommonGuessProto.CommonGuessRewardCompleteUserItem.newBuilder();
            userItem.setServerId(userBaseInfo.getUserBaseInfo().getServerId());
            userItem.setUserName(userBaseInfo.getUserBaseInfo().getNickName());//需要本地化
            userItem.setUserId(userBaseInfo.getUserId());
            respMsg.addCompleteUser(userItem);
        }
        return respMsg;
    }
}
